<?php

abstract class DbObject {
	
	private $_fields;
	private $_cols;
	private $_db;
	private $_pk;
	
	public function __construct($id = NULL) {
		$this->_fields = array();
		$this->_db = db::getInstance();
		foreach ($this->getColumns() as $column)
			$this->_fields[$column] = null;
		
		if (isset($id) && is_numeric($id)) {
			$this->getFields($id);
		}
	}
	
	public function __call($methodName, $arguments) {
		
		$property = strtolower(substr($methodName, 3));
		if ('get' == strtolower(substr($methodName, 0, 3))) {
			if (array_key_exists($property, $this->_fields))
				return $this->_fields[$property]; 
		}
		else if ('set' == strtolower(substr($methodName, 0, 3))) {
			if (array_key_exists($property, $this->_fields) && $property != 'id') {
				$value = (1 == count($arguments)) ? $arguments[0] : null; 
				$this->_fields[$property] = $value;
				return;
			}
		}
		throw new ErrorException('Call to an undefined method '. $methodName );	
	}
	
	public function getColumns() {
		if (!isset($this->_cols)) {
			$this->_cols = array();
			if (is_array($cols = db::getInstance()->performQuery('DESCRIBE '. get_class($this))->fetchAll(PDO::FETCH_OBJ))) {
				foreach ($cols as $col) {
					if ($col->Key == 'PRI')
						$this->_pk = strtolower($col->Field);
					$this->_cols[] = strtolower($col->Field);
				}	
			}
			else {
				throw new ErrorException('Table does not exist in database');
			}
		}
		return $this->_cols;
	}
	
	private function getFields($id) {
		if ($obj = $this->_db->performQuery('SELECT * FROM '. get_class($this) .' WHERE `id` = :id', array(':id' => $id))) {
			if ($field_data = $obj->fetch(PDO::FETCH_ASSOC)) {
				foreach ($field_data as $columnName => $value) {
					$this->_fields[strtolower($columnName)] = $value;
				}
			}
		}
	}
	
	public function commit() {
		if ($this->existInDB())
			$this->update();
		else {
			$this->insert();
		}
	}
	
	public function existInDb() {
		if (!is_null($this->getId()) && is_numeric($this->getId())) {
			$objClass = get_class($this);
			$obj = new $objClass($this->getId());
			if (!is_null($this->getId()) && is_numeric($this->getId()) && $obj->getId() > 0)
				return true;
		}
		return false;
	}

	private function update() {
		$sqlStatement = '';
		$params = array();
		$columns = '';
		$columnValue = '';
		
		$sqlStatement .= 'UPDATE '. get_class($this);
		$sqlStatement .= ' SET ';
		foreach ($this->getColumns() as $col) {
			$methodName = 'get'.$col;
			if ($col == $this->_pk || is_null($this->$methodName()))
				continue;
			$columns .= '`'.$col.'`=:'.$col.',';
			$params[$col] = $this->$methodName();
		}
		$columns = rtrim($columns, ',');
		
		$sqlStatement .= $columns;
		
		$sqlStatement .= ' WHERE `'. $this->_pk.'`='.$this->getId();
		
		$this->_db->performQuery($sqlStatement, $params);
	}
	
	private function insert() {
		
		$sqlStatement = '';
		$params = array();
		$columns = '';
		$columnValue = '';
		
		$sqlStatement .= 'INSERT INTO '. get_class($this);
		$sqlStatement .= ' (';
		foreach ($this->getColumns() as $col) {
			$methodName = 'get'.$col;
			if ($col == $this->_pk || is_null($this->$methodName()))
				continue;
			$columns .= '`'.$col.'`,';
			$columnValue .= ':'.$col.',';
			$params[$col] = $this->$methodName();
		}
		$columns = rtrim($columns, ',');
		$columnValue = rtrim($columnValue, ',');
		
		$sqlStatement .= $columns;
		$sqlStatement .= ')';
		
		$sqlStatement .= ' VALUES(';
		$sqlStatement .= $columnValue;
		$sqlStatement .= ')';
		
		$this->_db->performQuery($sqlStatement, $params);
		$this->getFields($this->_db->getLastId());
	}
}